﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using A2DFramework.CacheService.Coordinator.Wrappers;
using A2DFramework.CacheService.CacheProvider.LocalCache;
using A2DFramework.EventService;
using A2DFramework.CacheService.CacheEvents;
using A2DFramework.InstanceService;

namespace A2DFramework.CacheService.Coordinator
{
    class CacheCoordinator : ICacheCoordinator
    {
        private string location;
        private CacheServerWrapper backupCacheServer;
        private CacheServersWrapper peerCacheServer;
        private LocalCacheWrapper localCacheWrapper;
        private IEventBus evtBus;

        public CacheCoordinator(string location)
        {
            this.location = location;

            this.evtBus = ObjectFactory.Resolve<IEventBus>();

            if (Configuration.CacheConfiguration.Storages[location].DistributedCacheSetting_BackupCacheServer != null)
            {
                this.backupCacheServer = new CacheServerWrapper(Configuration.CacheConfiguration.Storages[location].DistributedCacheSetting_BackupCacheServer);
            }

            if (Configuration.CacheConfiguration.Storages[location].DistributedCacheSetting_PeerCacheServers != null
                && Configuration.CacheConfiguration.Storages[location].DistributedCacheSetting_PeerCacheServers.Count > 0)
            {
                this.peerCacheServer = new CacheServersWrapper(Configuration.CacheConfiguration.Storages[location].DistributedCacheSetting_PeerCacheServers);
            }

            this.localCacheWrapper = new LocalCacheWrapper(LocalCacheFactory.Generate(Configuration.CacheConfiguration.Storages[location].LocalCacheSetting_CacheAlgorithm, Configuration.CacheConfiguration.Storages[location].LocalCacheSetting_CacheCapacity));
        }

        public void Put(string key, object value, CacheExpireType expireType, double increment)
        {
            localCacheWrapper.Put(key, value, expireType, increment);

            if (this.peerCacheServer != null)
                peerCacheServer.Put(key, value, expireType, increment);

            if (backupCacheServer != null)
                backupCacheServer.Put(key, value, expireType, increment);

            TriggerCachePutEvent(key);
        }


        public object Get(string key)
        {
            object o = localCacheWrapper.Get(key);
            if (o != null)
                return o;

            o = GetRemote(key);
            return o;
        }

        public object GetRemote(string key)
        {
            object o = null;

            if (this.peerCacheServer != null)
                o = peerCacheServer.Get(key);

            if (o != null)
                return o;

            if (backupCacheServer != null)
                o = backupCacheServer.Get(key);
            return o;
        }

        public void Remove(string key)
        {
            localCacheWrapper.Remove(key);

            if (this.peerCacheServer != null)
                peerCacheServer.Remove(key);

            if (backupCacheServer != null)
                backupCacheServer.Remove(key);

            TriggerCacheRemoveEvent(key);
        }
        private void TriggerCachePutEvent(string key)
        {
            CachePutEvent evt = new CachePutEvent()
            {
                Key = key,
                Location = this.location
            };
            evtBus.Publish<CachePutEvent>(evt);
        }

        private void TriggerCacheRemoveEvent(string key)
        {
            CacheRemovedEvent evt = new CacheRemovedEvent()
            {
                Key = key,
                Location = this.location
            };
            evtBus.Publish<CacheRemovedEvent>(evt);
        }
    }
}
